package net.sharpf2.api.interfaces;

import java.util.ArrayList;
import net.sharpf2.sfcore.client.Interface;
import net.sharpf2.api.game.Interfaces;
import net.sharpf2.api.types.Content;
import net.sharpf2.api.info.Item;

/**
 * Class to handle the inventory interface
 * @author Rick van Biljouw
 * @author Drew Lindsey
 */
public class Inventory {

    /**
     * Return the actual interface object for the inventory
     * @return Content<Interface>
     */
    public static Content<Interface> getInterface() {
        if (!Bank.isOpen()) {
            return Interfaces.get(Constants.INVENTORY_TAB, 0);
        }
        return Interfaces.get(763, 0); //BANK INVENTORY
    }

    /**
     * Returns the children of the inventory tab.
     * @param   child   int Child ID.
     * @return  Content<Interface>
     */
    public static Content<Interface> getChild(int child) {
        return Interfaces.get(Constants.INVENTORY_TAB, child);
    }

    /**
     * Returns all items in the inventory
     * @return items
     */
    public static Item[] getItems() {
        if (!Bank.isOpen()) {
            Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        }
        ArrayList<Item> items = new ArrayList<Item>();
        for (Interface child : getInterface().getContent().getChildren()) {
            if (child != null && child.getId() > 0) {
                items.add(new Item(new Content<Interface>(child)));
            }
        }
        return items.toArray(new Item[items.size()]);
    }

    /**
     * Returns the amount of items in the inventory
     * @return item amount
     */
    public static int getItemCount() {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        return getItems().length;
    }

    /**
     * Checks if inventory is full.
     * @return  True if is full, otherwise false.
     */
    public static boolean isFull() {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        return getItemCount() >= 28;
    }

    /**
     * Gets the count of an item in the inventory
     * @param   id                  id of the item
     * @param   includeStackSize    whether or not stack size should be included
     * @return  item count in inventory
     */
    public static int getCount(int id, boolean includeStackSize) {
        if (!Bank.isOpen()) {
            Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        }
        int counts = 0;
        for (Item i : getItems()) {
            if (i.getId() == id) {
                counts++;
            }
        }
        if (includeStackSize) {
            Item item = findItem(id);
            if (item != null) {
                counts += item.getStackSize();
            }
        }
        return counts;
    }

    /**
     * Gets the count of an item in the inventory
     * @param   ids                 id of the item
     * @param   includeStackSize    whether or not stack size should be included
     * @return  item count in inventory
     */
    public static int getCount(boolean includeStackSize, int... ids) {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        if (includeStackSize) {
            Item item = findItem(ids);
            if (item != null) {
                return item.getStackSize();
            }
            return 0;
        } else {
            ArrayList<Item> items = new ArrayList<Item>();
            for (Item i : getItems()) {
                boolean valid = false;
                for (int id : ids) {
                    if (i.getId() == id) {
                        valid = true;
                    }
                }

                if (valid) {
                    items.add(i);
                }

            }
            return items.size();
        }
    }

    /**
     * Counts every item in inventory, except items with given IDs.
     * @param   ids items not to count.
     * @return  Amount of items.
     */
    public static int getCountExcept(int... ids) {
        int counter = 0;
        for (Item item : getItems()) {
            boolean valid = true;
            for (int id : ids) {
                if (item.getId() == id) {
                    valid = false;
                }
            }
            if (valid) {
                counter++;
            }
        }
        return counter;
    }

    /**
     * Checks if the inventory contains and item with given id
     * @param   ids   Item ids in question
     * @return  True if item exists, false otherwise
     */
    public static boolean containsAny(int... ids) {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        return findItem(ids) != null;
    }

    /**
     * Gets an Item from the inventory.
     * @param   ids Specified item ids.
     * @return  The first Item with a matching, if no items found returns null.
     */
    public static Item findItem(int... ids) {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        for (Item i : getItems()) {
            for (int filterId : ids) {
                if (i.getId() == filterId) {
                    return i;
                }
            }
        }
        return null;
    }

    /**
     * Interacts with every item with the specified item id.
     * @param   ids     Specific id of the item to interact with.
     * @param   action  Action to perform on the item.
     * @return  Interface
     */    
    public static Interface interact(final String action, final int... ids) {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);

        final Interface[] children = Interfaces.get(Inventory.Constants.INVENTORY_TAB, 0).getContent().getChildren();
        for (int i = 0; i < children.length; i++) {
            final int id = children[i].getId();
            for (final int aid : ids) {
                if (id == aid) {
                    final Item item = new Item(new Content<Interface>(children[i]));
                    item.interact(action);
                    return item.getContent();
                }
            }
        }
        return null;
    }

    /**
     * Drops all items except the ones with the specified id.
     * @param ids   IDs of items to keep.
     */
    public static void dropAllExcept(int... ids) {
        Tabs.checkAndOpen(Tabs.Constants.TAB_INVENTORY);
        for (Item i : getItems()) {
            boolean canDrop = true;

            for (int id : ids) {
                if (i.getId() == id) {
                    canDrop = false;
                }
            }

            if (canDrop) {
                i.interact("(Drop|Fallen lassen|Poser)");
            }
        }
    }

    public static class Constants {

        public static final int INVENTORY_TAB = 679;
    }
}
